package com.ruyuan.gateway.sdk.facade.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.common.utils.MD5Utils;
import com.ruyuan.gateway.sdk.facade.RuyuanGatewayFacade;
import com.ruyuan.gateway.sdk.model.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static com.ruyuan.gateway.sdk.model.GatewayConstants.*;

/**
 * @author xx
 */
@Component
@Slf4j
public class RuyuanGatewayFacadeImpl implements RuyuanGatewayFacade {

    @Resource(name = "gatewayRedisTemplate")
    private RedisTemplate gatewayRedisTemplate;

    @Autowired
    private GatewaySDKProperties gatewaySDKProperties;

    @Resource(name = "gatewayConfigService")
    private ConfigService configService;

    @Override
    public boolean reportApiAuthorityRequirement(List<ApiAuthorizationRequireInfo> apiAuthorizationRequireInfoList) {
        try {
            String currentMd5 = null;
            String content = configService.getConfig(API_FILTER_CHAIN_DATA_ID, API_FILTER_CHAIN_GROUP_ID, 3000);
            if (StringUtils.isNotBlank(content)) {
                currentMd5 = MD5Utils.md5Hex(content.getBytes());
            }
            // 网关的接口不需要登录，这个定义需要放在最前面
            ArrayList<ApiAuthorizationRequireInfo> finalList = new ArrayList<>();
            ApiAuthorizationRequireInfo info = new ApiAuthorizationRequireInfo();
            info.setPath("/api/gateway/**");
            info.setNeedLogin(false);
            info.setPriority(Integer.MIN_VALUE);
            finalList.add(info);
            // 再加上业务接口
            finalList.addAll(apiAuthorizationRequireInfoList.stream().filter(
                    requireInfo -> StringUtils.isNotBlank(requireInfo.getPath())
            ).collect(Collectors.toList()));
            configService.publishConfigCas(API_FILTER_CHAIN_DATA_ID, API_FILTER_CHAIN_GROUP_ID, JSON.toJSONString(finalList, SerializerFeature.PrettyFormat), currentMd5);
            return true;
        } catch (Exception e) {
            throw new GatewayException("report api authority requirement fail", e);
        }
    }

    @Override
    public boolean reportUserAuthorities(UserAuthorities userAuthorities) {
        try {
            BoundValueOperations operations = gatewayRedisTemplate.boundValueOps(USER_AUTH_PREFIX + userAuthorities.getUserId());
            operations.set(userAuthorities, Duration.ofMillis(gatewaySDKProperties.getSessionTimeout() + 300000L));
            return true;
        } catch (Exception e) {
            throw new GatewayException("report user authorities fail", e);
        }
    }

    @Override
    public boolean login(AccountInfoToken token) {
        try {
            SecurityUtils.getSubject().login(token);
        } catch (AuthenticationException e) {
            log.error("login failed username:{} ", token.getUsername(), e);
            return false;
        }
        return true;
    }

    @Override
    public boolean logout() {
        gatewayRedisTemplate.delete(USER_AUTH_PREFIX + getCurrentUser().getUserId());
        SecurityUtils.getSubject().logout();
        return true;
    }

    @Override
    public UserAccountInfo getCurrentUser() {
        return (UserAccountInfo) SecurityUtils.getSubject().getPrincipal();
    }
}
